//! 允许选择一个值的表示法。
//!
//! 例如，要一个结构，部分字段可能是引用、可能不是。有许多方法实现：
//!
//! - 使用枚举，包括 `Cow`。缺点：不静态。
//! - 写多个结构，在 trait 中实现方法。缺点：trait 的 `impl` 返回值尚未稳定。
//! - 把字段的类型，通过泛型传入。缺点：具体类型会通过泛型泄露出去。
//!
//! 使用 [`Repr`]，可以由一个“开关”（如 [`OwnRepr`]），通过 GAT，选择不同的表示方法。

pub trait Repr {
    type Wrap<'a, T: 'a>;
}
pub trait ReprUsz: Repr {
    type WrapUsz<'a, T: ?Sized + 'a>;
}
impl<T: ReprUsz> Repr for T {
    type Wrap<'a, U: 'a> = T::WrapUsz<'a, U>;
}

macro_rules! genTrait {
    ($macro: ident $trait: ident $f: ident $(& $mut: ident)? $(? $sized: ident)? $wrap: ident : $($sup: ident),+) => {
        macro_rules! $macro {
            (@item $arg: ident $then: tt) => {
                fn $f<'a, 'b: 'a, T: 'b + $(? $sized)*>(
                    $arg: &'a $($mut)? Self::$wrap<'b, T>
                ) -> &'a $($mut)? T
                $then
            };
            ($ty: ty) => {
                impl $trait for $ty {
                    $macro!(@item repr { repr });
                }
            };
        }

        pub trait $trait: $($sup +)+ {
            $macro!(@item repr ;);
        }
    };
}

genTrait!(implRef ReprRef borrow Wrap : Repr);
genTrait!(implRefUsz ReprRefUsz borrow_unsized ?Sized WrapUsz : ReprRef, ReprUsz);
genTrait!(implMut ReprMut borrow_mut &mut Wrap : ReprRef);
genTrait!(implMutUsz ReprMutUsz borrow_mut_unsized &mut ?Sized WrapUsz : ReprMut, ReprRefUsz);

pub struct RefRepr {}
impl ReprUsz for RefRepr {
    type WrapUsz<'a, T: ?Sized + 'a> = &'a T;
}
implRef!(RefRepr);
implRefUsz!(RefRepr);

pub struct MutRepr {}
impl ReprUsz for MutRepr {
    type WrapUsz<'a, T: ?Sized + 'a> = &'a mut T;
}
implRef!(MutRepr);
implRefUsz!(MutRepr);
implMut!(MutRepr);
implMutUsz!(MutRepr);

pub struct OwnRepr {}
impl Repr for OwnRepr {
    type Wrap<'a, T: 'a> = T;
}
implRef!(OwnRepr);
implMut!(OwnRepr);

pub struct BoxRepr {}
impl ReprUsz for BoxRepr {
    type WrapUsz<'a, T: ?Sized + 'a> = Box<T>;
}
implRef!(BoxRepr);
implRefUsz!(BoxRepr);
implMut!(BoxRepr);
implMutUsz!(BoxRepr);
